home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / JTextField.java < prev    next >
Text File  |  1998-06-30  |  20KB  |  593 lines

  1. /*
  2.  * @(#)JTextField.java    1.48 98/04/14
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing;
  21.  
  22. import java.awt.*;
  23. import java.awt.event.*;
  24. import com.sun.java.swing.text.*;
  25. import com.sun.java.swing.plaf.*;
  26. import com.sun.java.swing.event.*;
  27. import com.sun.java.accessibility.*;
  28.  
  29. /**
  30.  * JTextField is a lightweight component that allows the editing 
  31.  * of a single line of text.  It is intended to be source-compatible
  32.  * with java.awt.TextField where it is reasonable to do so.  This
  33.  * component has capabilities not found in the java.awt.TextField 
  34.  * class.  The superclass should be consulted for additional capabilities.
  35.  * <p>
  36.  * JTextField has a method to establish the string used as the
  37.  * command string for the action event that gets fired.  The
  38.  * java.awt.TextField used the text of the field as the command
  39.  * string for the ActionEvent.  JTextField will use the command
  40.  * string set with the <code>setActionCommand</code> method if not null, 
  41.  * otherwise it will use the text of the field as a compatibility with 
  42.  * java.awt.TextField.
  43.  * <p>
  44.  * The method <code>setEchoChar</code> and <code>getEchoChar</code>
  45.  * are not provided directly to avoid a new implementation of a
  46.  * pluggable look-and-feel inadvertantly exposing password characters.
  47.  * To provide password-like services a seperate class JPasswordField
  48.  * extends JTextField to provide this service with an independantly
  49.  * pluggable look-and-feel.
  50.  * <p>
  51.  * The java.awt.TextField could be monitored for changes by adding
  52.  * a TextListener for TextEvent's.  In the JTextComponent based
  53.  * components, changes are broadcasted from the model via a
  54.  * DocumentEvent to DocumentListeners.  The DocumentEvent gives 
  55.  * the location of the change and the kind of change if desired.
  56.  * The code fragment might look something like:
  57.  * <pre><code>
  58.  *    DocumentListener myListener = ??;
  59.  *    JTextField myArea = ??;
  60.  *    myArea.getDocument().addDocumentListener(myListener);
  61.  * </code></pre>
  62.  * <p>
  63.  * The horizontal alignment of JTextField can be set to be left
  64.  * justified, centered, or right justified if the required size
  65.  * of the field text is smaller than the size allocated to it.
  66.  * This is determined by the <code>setHorizontalAlignment</code>
  67.  * and <code>getHorizontalAlignment</code> methods.  The default
  68.  * is to be left justified.
  69.  * <p>
  70.  * For the keyboard keys used by this component in the standard Look and
  71.  * Feel (L&F) renditions, see the
  72.  * <a href="doc-files/Key-Index.html#JTextField">JTextField</a> key assignments.
  73.  * <p>
  74.  * Customized fields can easily be created by extending the model and
  75.  * changing the default model provided.  For example, the following piece
  76.  * of code will create a field that holds only upper case characters.  It
  77.  * will work even if text is pasted into from the clipboard or it is altered via 
  78.  * programmatic changes.
  79.  * <pre><code>
  80.  
  81. public class UpperCaseField extends JTextField {
  82.  
  83.     public UpperCaseField(int cols) {
  84.     super(cols);
  85.     }
  86.  
  87.     protected Document createDefaultModel() {
  88.     return new UpperCaseDocument();
  89.     }
  90.  
  91.     static class UpperCaseDocument extends PlainDocument {
  92.  
  93.         public void insertString(int offs, String str, AttributeSet a) 
  94.         throws BadLocationException {
  95.  
  96.         if (str == null) {
  97.         return;
  98.         }
  99.         char[] upper = str.toCharArray();
  100.         for (int i = 0; i < upper.length; i++) {
  101.         upper[i] = Character.toUpperCase(upper[i]);
  102.         }
  103.         super.insertString(offs, new String(upper), a);
  104.     }
  105.     }
  106. }
  107.  
  108.  * </code></pre>
  109.  * <p>
  110.  * Warning: serialized objects of this class will not be compatible with
  111.  * future swing releases.  The current serialization support is appropriate
  112.  * for short term storage or RMI between Swing1.0 applications.  It will
  113.  * not be possible to load serialized Swing1.0 objects with future releases
  114.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  115.  * baseline for the serialized form of Swing objects.
  116.  *
  117.  * @beaninfo
  118.  *   attribute: isContainer false
  119.  *
  120.  * @author  Timothy Prinzing
  121.  * @version 1.48 04/14/98
  122.  * @see #setActionCommand
  123.  * @see JPasswordField
  124.  */
  125. public class JTextField extends JTextComponent implements SwingConstants {
  126.  
  127.     /**
  128.      * Constructs a new TextField.  A default model is created, the initial
  129.      * string is null, and the number of columns is set to 0.
  130.      */
  131.     public JTextField() {
  132.         this(null, null, 0);
  133.     }
  134.  
  135.     /**
  136.      * Constructs a new TextField initialized with the specified text.
  137.      * A default model is created and the number of columns is 0.
  138.      *
  139.      * @param text the text to be displayed, or null
  140.      */
  141.     public JTextField(String text) {
  142.         this(null, text, 0);
  143.     }
  144.  
  145.     /**
  146.      * Constructs a new empty TextField with the specified number of columns.
  147.      * A default model is created and the initial string is set to null.
  148.      *
  149.      * @param columns  the number of columns to use to calculate 
  150.      *   the preferred width.  If columns is set to zero, the
  151.      *   preferred width will be whatever naturally results from
  152.      *   the component implementation.
  153.      */ 
  154.     public JTextField(int columns) {
  155.         this(null, null, columns);
  156.     }
  157.  
  158.     /**
  159.      * Constructs a new TextField initialized with the specified text
  160.      * and columns.  A default model is created.
  161.      *
  162.      * @param text the text to be displayed, or null
  163.      * @param columns  the number of columns to use to calculate 
  164.      *   the preferred width.  If columns is set to zero, the
  165.      *   preferred width will be whatever naturally results from
  166.      *   the component implementation.
  167.      */
  168.     public JTextField(String text, int columns) {
  169.         this(null, text, columns);
  170.     }
  171.  
  172.     /**
  173.      * Constructs a new JTextField that uses the given text storage
  174.      * model and the given number of columns.  This is the constructor
  175.      * through which the other constructors feed.  If the document is null,
  176.      * a default model is created.
  177.      *
  178.      * @param doc  the text storage to use.  If this is null, a default
  179.      *   will be provided by calling the createDefaultModel method.
  180.      * @param text  the initial string to display, or null
  181.      * @param columns  the number of columns to use to calculate 
  182.      *   the preferred width >= 0.  If columns is set to zero, the
  183.      *   preferred width will be whatever naturally results from
  184.      *   the component implementation.
  185.      * @exception IllegalArgumentException if columns < 0
  186.      */
  187.     public JTextField(Document doc, String text, int columns) {
  188.         if (columns < 0) {
  189.             throw new IllegalArgumentException("columns less than zero.");
  190.         }
  191.         visibility = new DefaultBoundedRangeModel();
  192.         visibility.addChangeListener(new ScrollRepainter());
  193.         this.columns = columns;
  194.         if (doc == null) {
  195.             doc = createDefaultModel();
  196.         }
  197.         setDocument(doc);
  198.         if (text != null) {
  199.             setText(text);
  200.         }
  201.     }
  202.  
  203.     /**
  204.      * Gets the class ID for a UI.
  205.      *
  206.      * @return the ID ("TextFieldUI")
  207.      * @see JComponent#getUIClassID
  208.      * @see UIDefaults#getUI
  209.      */
  210.     public String getUIClassID() {
  211.         return "TextFieldUI";
  212.     }
  213.  
  214.     
  215.     /**
  216.      * Calls to revalidate that come from within the textfield itself will
  217.      * be handled by validating the textfield. 
  218.      * 
  219.      * @see JComponent#revalidate
  220.      * @see JComponent#isValidateRoot
  221.      */
  222.     public boolean isValidateRoot() {
  223.         return true;
  224.     }
  225.  
  226.  
  227.     /**
  228.      * Returns the horizontal alignment of the text.
  229.      * Valid keys: JTextField.LEFT (the default), JTextField.CENTER,
  230.      * JTextField.RIGHT.
  231.      *
  232.      * @return the alignment
  233.      */
  234.     public int getHorizontalAlignment() {
  235.         return horizontalAlignment;
  236.     }
  237.     
  238.     /**
  239.      * Sets the horizontal alignment of the text.
  240.      * Valid keys: JTextField.LEFT (the default), JTextField.CENTER,
  241.      * JTextField.RIGHT.  invalidate() and repaint() are called when the
  242.      * alignment is set, and a PropertyChange event ("horizontalAlignment")
  243.      * is fired.
  244.      *
  245.      * @param alignment the alignment
  246.      * @exception IllegalArgumentException if the alignment
  247.      *  specified is not a valid key.
  248.      * @beaninfo
  249.      *   preferred: true
  250.      *       bound: true
  251.      * description: Set the field alignment to LEFT (the default), CENTER, RIGHT
  252.      *        enum: LEFT JTextField.LEFT CENTER JTextField.CENTER RIGHT JTextField.RIGHT
  253.      */
  254.      public void setHorizontalAlignment(int alignment) {
  255.         if (alignment == horizontalAlignment) return;
  256.         int oldValue = horizontalAlignment;
  257.         if ((alignment == LEFT) || (alignment == CENTER) || (alignment == RIGHT)) {
  258.             horizontalAlignment = alignment;
  259.         } else {
  260.             throw new IllegalArgumentException("horizontalAlignment");
  261.         }
  262.         firePropertyChange("horizontalAlignment", oldValue, horizontalAlignment);       
  263.         invalidate();
  264.         repaint();
  265.     }
  266.  
  267.     /**
  268.      * Creates the default implementation of the model
  269.      * to be used at construction if one isn't explicitly 
  270.      * given.  An instance of PlainDocument is returned.
  271.      *
  272.      * @return the default model implementation
  273.      */
  274.     protected Document createDefaultModel() {
  275.         return new PlainDocument();
  276.     }
  277.  
  278.     /**
  279.      * Returns the number of columns in this TextField.
  280.      *
  281.      * @return the number of columns >= 0
  282.      */
  283.     public int getColumns() {
  284.         return columns;
  285.     }
  286.  
  287.     /**
  288.      * Sets the number of columns in this TextField, and then invalidate
  289.      * the layout.
  290.      *
  291.      * @param columns the number of columns >= 0
  292.      * @exception IllegalArgumentException if columns is less than 0
  293.      * @beaninfo
  294.      * description: the number of columns preferred for display
  295.      */
  296.     public void setColumns(int columns) {
  297.         int oldVal = this.columns;
  298.         if (columns < 0) {
  299.             throw new IllegalArgumentException("columns less than zero.");
  300.         }
  301.         if (columns != oldVal) {
  302.             this.columns = columns;
  303.             invalidate();
  304.         }
  305.     }
  306.  
  307.     /**
  308.      * Gets the column width.
  309.      * The meaning of what a column is can be considered a fairly weak
  310.      * notion for some fonts.  This method is used to define the width
  311.      * of a column.  By default this is defined to be the width of the
  312.      * character <em>m</em> for the font used.  This method can be 
  313.      * redefined to be some alternative amount
  314.      *
  315.      * @return the column width >= 1
  316.      */
  317.     protected int getColumnWidth() {
  318.         if (columnWidth == 0) {
  319.             FontMetrics metrics = getFontMetrics(getFont());
  320.             columnWidth = metrics.charWidth('m');
  321.         }
  322.         return columnWidth;
  323.     }
  324.  
  325.     /**
  326.      * Returns the preferred size Dimensions needed for this 
  327.      * TextField.  If a non-zero number of columns has been
  328.      * set, the width is set to the columns multiplied by
  329.      * the column width. 
  330.      *
  331.      * @return the dimensions
  332.      */
  333.     public Dimension getPreferredSize() {
  334.         synchronized (getTreeLock()) {
  335.             Dimension size = super.getPreferredSize();
  336.             if (columns != 0) {
  337.                 size.width = columns * getColumnWidth();
  338.             }
  339.             return size;
  340.         }
  341.     }
  342.  
  343.     /**
  344.      * Returns the minimum size Dimensions needed for this 
  345.      * TextField.  This defaults to the preferred size.
  346.      *
  347.      * @return the dimensions
  348.      */
  349.     public Dimension getMinimumSize() {
  350.         return getPreferredSize();
  351.     }
  352.  
  353.     /**
  354.      * Sets the current font.  This removes cached row height and column
  355.      * width so the new font will be reflected.  revalidate() is called
  356.      * after setting the font.
  357.      *
  358.      * @param f the new font
  359.      */
  360.     public void setFont(Font f) {
  361.         super.setFont(f);
  362.         columnWidth = 0;
  363.         revalidate();
  364.     }
  365.  
  366.     /**
  367.      * Adds the specified action listener to receive 
  368.      * action events from this textfield.
  369.      *
  370.      * @param l the action listener
  371.      */ 
  372.     public synchronized void addActionListener(ActionListener l) {
  373.         listenerList.add(ActionListener.class, l);
  374.     }
  375.  
  376.     /**
  377.      * Removes the specified action listener so that it no longer
  378.      * receives action events from this textfield.
  379.      *
  380.      * @param l the action listener 
  381.      */ 
  382.     public synchronized void removeActionListener(ActionListener l) {
  383.         listenerList.remove(ActionListener.class, l);
  384.     }
  385.  
  386.     /**
  387.      * Notifies all listeners that have registered interest for
  388.      * notification on this event type.  The event instance 
  389.      * is lazily created using the parameters passed into 
  390.      * the fire method.  The listener list is processed in last to
  391.      * first order.
  392.      * @see EventListenerList
  393.      */
  394.     protected void fireActionPerformed() {
  395.         // Guaranteed to return a non-null array
  396.         Object[] listeners = listenerList.getListenerList();
  397.         ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
  398.                                         (command != null) ? command : getText());
  399.         // Process the listeners last to first, notifying
  400.         // those that are interested in this event
  401.         for (int i = listeners.length-2; i>=0; i-=2) {
  402.             if (listeners[i]==ActionListener.class) {
  403.                 ((ActionListener)listeners[i+1]).actionPerformed(e);
  404.             }          
  405.         }
  406.     }
  407.  
  408.     /**
  409.      * Sets the command string used for action events.
  410.      *
  411.      * @param command the command string
  412.      */
  413.     public void setActionCommand(String command) {
  414.         this.command = command;
  415.     }
  416.  
  417.     /**
  418.      * Fetches the command list for the editor.  This is
  419.      * the list of commands supported by the plugged-in UI
  420.      * augmented by the collection of commands that the
  421.      * editor itself supports.  These are useful for binding
  422.      * to events, such as in a keymap.
  423.      *
  424.      * @return the command list
  425.      */
  426.     public Action[] getActions() {
  427.         return TextAction.augmentList(super.getActions(), defaultActions);
  428.     }
  429.  
  430.     /** 
  431.      * Processes action events occurring on this textfield by
  432.      * dispatching them to any registered ActionListener objects.
  433.      * This is normally called by the controller registered with
  434.      * textfield.
  435.      */  
  436.     public void postActionEvent() {
  437.         fireActionPerformed();
  438.     }
  439.  
  440.     /**
  441.      * Returns the String of parameters for this JTextField (columns + command
  442.      * string).
  443.      *
  444.      * @return the string of parameters
  445.      */
  446.     protected String paramString() {
  447.         return super.paramString() + ",columns=" + columns + 
  448.             ",command=" + command;
  449.     }
  450.  
  451.     // --- Scrolling support -----------------------------------
  452.  
  453.     /**
  454.      * Gets the visibility of the text field.  This can
  455.      * be adjusted to change the location of the visible
  456.      * area if the size of the field is greater than
  457.      * the area that was allocated to the field.
  458.      *
  459.      * The fields look-and-feel implementation manages
  460.      * the values of the minimum, maximum, and extent
  461.      * properties on the BoundedRangeModel.
  462.      * 
  463.      * @return the visibility
  464.      * @see BoundedRangeModel
  465.      */
  466.     public BoundedRangeModel getHorizontalVisibility() {
  467.         return visibility;
  468.     }
  469.  
  470.     /**
  471.      * Gets the scroll offset.
  472.      *
  473.      * @return the offset >= 0
  474.      */
  475.     public int getScrollOffset() {
  476.         return visibility.getValue();
  477.     }
  478.  
  479.     /**
  480.      * Sets the scroll offset.
  481.      *
  482.      * @param scrollOffset the offset >= 0
  483.      */
  484.     public void setScrollOffset(int scrollOffset) {
  485.         visibility.setValue(scrollOffset);
  486.     }
  487.     
  488.     /**
  489.      * Scrolls the field left or right.
  490.      *
  491.      * @param r the region to scroll
  492.      */
  493.     public void scrollRectToVisible(Rectangle r) {
  494.         // convert to coordinate system of the bounded range
  495.         int x = r.x + visibility.getValue();
  496.         if (x < visibility.getValue()) {
  497.             // Scroll to the left
  498.             visibility.setValue(x - 2);
  499.         } else if(x > visibility.getValue() + visibility.getExtent()) {
  500.             // Scroll to the right
  501.             visibility.setValue(x - visibility.getExtent() + 2);
  502.         }
  503.     }
  504.  
  505.     // --- variables -------------------------------------------
  506.  
  507.     /**
  508.      * Name of the action to send notification that the
  509.      * contents of the field have been accepted.  Typically
  510.      * this is bound to a carriage-return.
  511.      */
  512.     public static final String notifyAction = "notify-field-accept";
  513.  
  514.     private BoundedRangeModel visibility;
  515.     private int horizontalAlignment  = LEFT;
  516.     private int columns;
  517.     private int columnWidth;
  518.     private String command;
  519.  
  520.     private static final Action[] defaultActions = {
  521.         new NotifyAction()
  522.     };
  523.  
  524.     // --- Action implementations -----------------------------------
  525.  
  526.     static class NotifyAction extends TextAction {
  527.  
  528.         NotifyAction() {
  529.             super(notifyAction);
  530.         }
  531.  
  532.         public void actionPerformed(ActionEvent e) {
  533.             JTextComponent target = getFocusedComponent();
  534.             if (target instanceof JTextField) {
  535.                 JTextField field = (JTextField) target;
  536.                 field.postActionEvent();
  537.             }
  538.         }
  539.     }
  540.  
  541.     class ScrollRepainter implements ChangeListener {
  542.  
  543.         public void stateChanged(ChangeEvent e) {
  544.             repaint();
  545.         }
  546.  
  547.     }
  548.  
  549. /////////////////
  550. // Accessibility support
  551. ////////////////
  552.  
  553.  
  554.     /**
  555.      * Get the AccessibleContext associated with this JTextField.
  556.      * Creates a new context if necessary.
  557.      *
  558.      * @return the AccessibleContext of this JTextField
  559.      */
  560.     public AccessibleContext getAccessibleContext() {
  561.         if (accessibleContext == null) {
  562.             accessibleContext = new AccessibleJTextField();
  563.         }
  564.         return accessibleContext;
  565.     }
  566.  
  567.     /**
  568.      * The class used to obtain the accessible role for this object.
  569.      * <p>
  570.      * Warning: serialized objects of this class will not be compatible with
  571.      * future swing releases.  The current serialization support is appropriate
  572.      * for short term storage or RMI between Swing1.0 applications.  It will
  573.      * not be possible to load serialized Swing1.0 objects with future releases
  574.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  575.      * baseline for the serialized form of Swing objects.
  576.      */
  577.     protected class AccessibleJTextField extends AccessibleJTextComponent {
  578.  
  579.         /**
  580.          * Gets the state set of this object.
  581.          *
  582.          * @return an instance of AccessibleStateSet describing the states 
  583.          * of the object
  584.          * @see AccessibleState
  585.          */
  586.         public AccessibleStateSet getAccessibleStateSet() {
  587.             AccessibleStateSet states = super.getAccessibleStateSet();
  588.             states.add(AccessibleState.SINGLE_LINE);
  589.             return states;
  590.         }
  591.     }
  592. }
  593.